In this lecture, we're going to be taking a look at a feature in Roblox Studio called attributes.
Attributes, as the name implies, allows you to add an attribute to any instance in the game.
These attributes have a name, and they store a value, and this value can be accessed by any script
in the game.
You can basically think of it as like a global variable stored on a specific instance.
And these can be very useful for defining things such as custom properties for stuff in your game.
For example, if you had a gun and you wanted to track how much ammo was left in the magazine, you
could have an attribute and store that number.
Or if you wanted to store other stats for the gun, such as a reload duration, um, how much reserve
ammo is left?
You can also do that through attributes.
Now to add an attribute on an instance in studio, you can just select your attribute.
So for example, let me select the spawn location here.
And inside of the properties menu.
If we scroll down to the very bottom, there's going to be a section down here for attributes.
And to add a new one we can just hit this plus button.
And here we can define the name for the attribute and what type it's going to store.
So currently these are all the different types that attributes can store.
They can store strings booleans, numbers and some other Roblox data types such as vector threes, color
threes, keyframes and stuff like that.
You can't store functions or tables in here.
That's just a limitation of attributes.
But you can store all of these data types and attributes, and these should cover most use cases that
you would use attributes for.
So we could give a name for our attribute.
I'll just say whatever.
And this attribute is going to store a string so I can hit save.
And now you can see our attribute shows up inside of the properties window.
And currently it's storing an empty string.
But I can type some text in here like hello there.
And now I have stored this string with this particular instance which is my spawn location.
And it has the name of whatever.
So this is basically like a global variable.
For this particular instance we can also add attributes to instances through scripts.
And I'll show you how to do that right now.
So for example let's refer to the spawn location inside of the workspace.
And let's add another attribute on this instance.
And we do that using a function called set attribute.
And all we need to do is pass the name for the attribute and the value that we would like to store in
the attribute.
So let's call this attribute uh, whatever two.
And inside of this attribute let's store a value of like 100.
And then if I go and run this code here real quick, and then I take a look at my properties menu.
As you can see, my whatever two here attribute has showed up.
And it is storing the value of 100.
Now if you would like to retrieve and read the value stored in an attribute, we can go ahead and refer
to our spawn location and we have a get function called get attribute.
And we need to provide the name of the attribute that we would like to read the value from.
So we could read the value stored in whatever.
And then we could also read the value stored in whatever two.
So let's go ahead and print both of those out inside of the console.
So I'll print that.
And then let's go ahead and copy this code and print what is stored in whatever number two.
And then let's go ahead and run this code and see what prints.
And as you can see it prints.
Hello there.
And we get our value of 100 which is pretty cool.
Now if you wanted to grab all of the attributes stored on an instance, then we have another get function
and this one's called get attributes instead of get attribute.
And you don't need to pass anything to this, but this function is going to return a dictionary that
contains key value pairs.
The key is going to be the names of the attributes.
And then the value associated with that key is going to be whatever value is stored in that particular
attribute.
So let's go ahead and just print this out into the console.
So we'll run our code again.
And here we got our table.
And there it shows our first attribute which is whatever storing the string of hello there.
And then there is our other attribute with the value of 100.
If you would like to be able to get rid of an attribute on an instance, for example, let's say I don't
want this attribute of whatever two on my instance anymore.
Then I can just simply set the value to nil, and that will automatically delete and get rid of that
attribute on my instance.
So if we run this code and then we go to the properties window, as you can see our whatever two attribute
has disappeared because it got deleted.
And then if you wanted to get rid of attributes inside of the properties window inside of studio, there's
a little settings icon right here.
And you can click that and you're able to delete or rename the attribute as well.
Now since we want to make our games event driven as much as possible, there are some events that we
can go ahead and listen to relating to attributes.
So if we would like to listen for when an attribute changes on an instance, there is a property called
attribute change and it says this fires whenever an attribute is changed on the instance.
And we can go ahead and connect a function to this event.
And this function is going to be passed the name of the attribute that changed.
So we could call this attribute name.
And then we'll just print out something like.
Uh, attribute changed.
And after we have connected this function to listen to this event, let's go ahead and add some more
attributes to our spawn location.
So we can do set attribute.
Let's call this uh hello.
And this attribute will just store some random value.
And then let's go ahead and do it again set attribute.
Let's call this one uh some color.
And here we'll store a new color three.
So we'll just do like white or something like that.
And then let's go ahead and run this code.
And what you're going to see is that our attribute changed event has fired twice.
So attribute changed and attribute changed.
And actually let's go ahead and swap this string here to actually print out the name of the attribute
as well.
And then let's run that code.
And nothing printed because I think, yeah, these attributes are already here.
So since we tried to set these attributes that already exist with the same value, nothing happens.
So actually, let me just, uh, delete all of these real quick.
Oh, you can actually see that it's listening and it's printing.
Uh, that the attributes change.
That's kind of cool.
But if we go ahead and run this code again, what you're going to see is that hello.
Changed, uh, some color change and it also printed attribute changed.
I think I'm connecting a whole bunch of functions to this event.
So I think that's why that's printing a bunch.
Now, if you don't want to listen for when every single attribute on your instance changes and you only
want to listen to a specific attribute, we have another function for that.
And that function is called get attribute changed signal.
And you just need to pass the name of the attribute that you would like to listen to.
And this function will return an RGB script signal that we can connect to.
So let's say uh, we want to listen for when the hello attribute changes.
So we can pass our name of hello.
And then we can connect a function to this.
And we can just print something like the hello attribute changed.
And then let me go ahead and run this code.
So we're listening to that event.
And then if I change the value inside of hello I'll do like uh something like this.
Hit enter.
It's going to print the hello attribute changed which is pretty cool.
So as a simple exercise to get you started with attributes, I'd like for you to create a new part in
your workspace.
It doesn't have to be anything fancy.
And what I would like for you to do is I would like for you to listen for when this part is touched,
and every single time this part is touched, I want you to increment an attribute on the part that tells
us how many times it has been touched so far in the lifetime of a particular server.
So go ahead and spend a few minutes doing that, and then I'll show you my solution next.
So what I'm going to do is I'm just going to add a simple script inside of my part.
I'll make a variable for my part, which is script dot parent.
And what we want to go ahead and do is we want to listen for when our part is touched.
So we'll connect a function to that event.
And every single time this event fires, we want to go ahead and increment an attribute on our part
to represent how many times the part has been touched.
Now, one way we could do it is we could have a variable in here, and we could call this touch count,
and we could set it to zero.
And every single time this event fires, we can increment touch count by one.
And then on our part we can set an attribute.
And we could call this, uh, times touched.
And we could set it to the value of this touch count.
That's one way we could use this with attributes.
Or another way we could do it is that if we don't want to have any variable that keeps track in our
script, how many times this part was touched and we only want to do it through attributes, what we
can go ahead and do instead is we can make a variable here called touch count.
And that's going to be equal to our part.
And we're going to get the attribute of times touched.
Now when this function first executes this attribute is not going to exist.
So this is going to return the value of nil.
So if touch count is nil that means we can go ahead and initialize touch count with a value of zero.
Now a faster way of doing this without needing to use an if statement, is that we could add an Or statement
here and put a zero.
And now this zero value is acting as a default value.
So just in case this function right here returns nil, it'll instead see this or statement and see hey
there's a value here.
We're going to use this instead because this function returned nil.
And then afterwards we can go ahead and increment touched count by one.
And then we can go ahead and set that attribute on our part.
So now as we're playing the game I haven't touched the part yet, but you'll notice that the times touched
attribute is actually set to one.
And I believe that's probably because my part is unanchored and it touched the base plate, and that's
why I incremented.
But if I go ahead and walk over my part and start touching it, you're going to see that my times touched
attribute is increasing every single time I touched it, which is pretty cool.
And we are able to read this attribute from any other script on our game.
So if we had another script inside of Server Script service, it would be able to refer to this part
and use the get attribute function to read the attribute that is stored on this part.
We can see it here on the client, and if I swap to the server view and I select this part.
As you can see, the server can see this attribute on the part as well.
Now if I was on the client here and let's say the client added a new attribute, I'll just call this
example the client.
And any scripts on the client is going to see this attribute.
But if I swap to the server view, what you're going to notice is that of course the server does not
see that attribute because we applied or added the attribute on the client, and only the client can
see those client sided changes.
The reason attributes were added were to act as maybe an alternative or a replacement to the previous
way.
Developers used to store values on instances or share them across multiple scripts, and that was with
value objects.
So if I were to search value here, as you can see, there's a whole bunch of different instances in
the game such as Vector3 values, string value, object value.
And all of these different values here.
And if I were to add one of these in here, this is simply an instance that stores that particular value.
So for example, this stores a true or a false value.
Or if I were to add a keyframe value here, of course this stores a keyframe.
Now if you don't want to do it through these instances, and you would like for all of these values
to be stored directly on the instance, then you can do so with attributes.
So those are attributes in a nutshell.
You'll likely find them useful in many situations in your games.
And we're also going to be using attributes in our upcoming project.
So stay tuned and I will see you in the next lecture.